#pragma once


namespace Math
{
    template<typename T>
    inline T PI(void)
    {
        return T(3.1415926535897932384626433832795);
    }

    template<typename T>
    struct TRadian;

    template<typename T>
    struct TDegree;

    template<typename T>
    inline T ToRadian(T degree)
    {
        return degree * (PI<T>() / T(180));
    }

    template<typename T>
    inline T ToDegree(T radian)
    {
        return radian * (T(180) / PI<T>());
    }

    template<typename T>
    inline T Abs(T x)
    {
        return (x >= T(0)) ? x : -x;
    }

    //
    // Basic
    //

    template<typename T>
    struct TRadian
    {
        T value;

        explicit TRadian(T rad) : value(rad)
        {}

        TRadian(const TRadian<T>& copy) : value(copy.value)
        {
        }

        TRadian(const TDegree<T>& deg) : value(ToRadian(deg.value))
        {
        }

        TRadian& operator = (const TRadian<T>& copy)
        {
            value = copy.value;
            return *this;
        }

        TRadian& operator = (const TDegree<T>& deg)
        {
            value = ToRadian(deg.value);
            return *this;
        }
    };

    template<typename T>
    struct TDegree
    {
        T value;

        explicit TDegree(T rad) : value(rad)
        {}

        TDegree(const TDegree<T>& copy) : value(copy.value)
        {}

        TDegree(const TRadian<T>& rad) : value(ToDegree(rad.value))
        {}

        TDegree& operator = (const TDegree<T>& copy)
        {
            value = copy.value;
            return *this;
        }

        TDegree& operator = (const TRadian<T>& rad)
        {
            value = ToDegree(rad.value);
            return *this;
        }
    };

    //
    // Common
    //
    //	overflow constant arithmetic : disable
#	pragma warning(disable:4756)

    template<typename T>
    inline T Infinity(void)
    {
        return T(1e+256);
    }

    template<typename T>
    inline T NaN(void)
    {
        return Infinity<T>() / Infinity<T>();
    }
    //	overflow constant arithmetic : default
#	pragma warning(default:4756)

    template<typename T>
    inline T Epsilon(void)
    {
        return T(1.4013e-045);
    }

    template<typename T>
    inline T Epsilon2(void)
    {
        return T(0.001);
    }


    template<typename T>
    inline T Sin(T x)
    {
		return Platform::Math<T>::Sin(x);
    }

    template<typename T>
    inline T Cos(T x)
    {
		return Platform::Math<T>::Cos(x);
    }

    template <typename T>
    inline T Sign(T x)
    {
        if(x > T(0))
        {
            return T(1);
        }
        else if(x < T(0))
        {
            return T(-1);
        }
        else
        {
            return T(0);
        }
    }


    template<typename T>
    inline T Tan(const TRadian<T>& angle)
    {
        T x = angle.value;

        return x + (x * x * x * T(0.3333333333)) + (x * x * x * x * x * T(0.1333333333333)) + (x * x * x * x * x * x * x * T(0.0539682539));
    }

    template <typename T>
    inline T ArcTan(T x)
    {
        //0.41196981
        return x - (x * x * x * T(0.333333333333)) + (x * x * x * x * x * T(0.2)) - (x * x * x * x * x * x * x * T(0.1428571429)) + (x * x * x * x * x * x * x * x * x * T(0.111111111111)) - (x * x * x * x * x * x * x * x * x * x * x * T(0.0909090909));
    }

    template<typename T>
    inline T ArcTan2(T y, T x)
    {
        //T sgn = Sign(y) * Sign(x);
        //return Abs(ArcTan(y / x)) * sgn;

        //return ArcTan(y/x);

		return Platform::Math<T>::ArcTan2(y, x);
    }

    // ArcSin
    template <typename T>
    inline T ArcSin(T x)
    {
        const T One = 1;
        return ArcTan2(x, Sqrt(One - x * x));
    }

    template <typename T>
    T ArcCos(T x)
    {
        const T One = 1;
        return ArcTan2(Sqrt(One - x * x), x);
    }

    template<typename T>
    inline T Sqrt(T x)
    {
		return Platform::Math<T>::Sqrt(x);
    }

    template<typename T>
    inline T InverseSqrt(T x)
    {
        return T(1) / Sqrt(x);
    }

    template<typename T>
    inline T Min(T x, T y)
    {
        return x < y ? x : y;
    }

    template<typename T>
    inline T Max(T x, T y)
    {
        return x > y ? x : y;
    }

    //
    //Vector's
    //

    template<typename T>
    struct TVector2
    {
        enum ctor{null};

        typedef T Type;
        typedef T const& ConstType;
        T x, y;

        TVector2<T>(ctor){} // dont zero memory
        TVector2<T>(ConstType v = (T)0) : x(v), y(v){}
        explicit TVector2<T>(ConstType x, ConstType y) : x(x), y(y){}

        Type operator[](int i)
        { return (&x)[i]; }

        ConstType operator[](int i) const
        { return (&x)[i]; }
    };

    template<typename T>
    struct TVector3
    {
        enum ctor{null};

        typedef T Type;
        typedef T const& ConstType;
        T x, y, z;

        TVector3<T>(ctor){} // dont zero memory
        TVector3<T>(ConstType v = (T)0) : x(v), y(v), z(v){}
        explicit TVector3<T>(ConstType x, ConstType y, ConstType z) : x(x), y(y), z(z){}
        explicit TVector3<T>(const TVector2<T>& xy, ConstType z) : x(xy.x), y(xy.y), z(z){}

        Type& operator[](int i)
        { return (&x)[i]; }

        ConstType operator[](int i) const
        {
            return (&x)[i];
        }

		static const TVector3<T> Zero;
		static const TVector3<T> One;
		static const TVector3<T> UpY;
		static const TVector3<T> Infinity;
    };

	template<typename T>
	const TVector3<T> TVector3<T>::Zero(0);

	template<typename T>
	const TVector3<T> TVector3<T>::One(1);

	template<typename T>
	const TVector3<T> TVector3<T>::UpY(0, 1, 0);

	template<typename T>
	const TVector3<T> TVector3<T>::Infinity(Math::Infinity<T>());
	//
	//
	//
    template<typename T>
    struct TVector4
    {
        enum ctor{null};

        typedef T Type;
        typedef T const& ConstType;

        T x, y, z, w;

        TVector4<T>(ctor){} // dont zero memory
        TVector4<T>(ConstType v = (T)0) : x(v), y(v), z(v), w(v){}
        explicit TVector4<T>(ConstType x, ConstType y, ConstType z, ConstType w) : x(x), y(y), z(z), w(w){}
        explicit TVector4<T>(const TVector3<T>& xyz, ConstType w) : x(xyz.x), y(xyz.y), z(xyz.z), w(w){}
        explicit TVector4<T>(const TVector2<T>& xy, const TVector2<T>& zw) : x(xy.x), y(xy.y), z(zw.x), w(zw.y){}
        Type& operator[](int i)
        { return (&x)[i]; }

        ConstType operator[](int i) const
        { return (&x)[i]; }
    };

    template<typename T>
    struct TQuaternion
    {
        enum ctor{null};

        typedef T Type;
        typedef T const& ConstType;
        T x, y, z, w;

        TQuaternion<T>(ctor){} // dont zero memory
        TQuaternion<T>(void) : x((T)0), y((T)0), z((T)0), w((T)1){}
        explicit TQuaternion<T>(ConstType v) : x(v), y(v), z(v), w(v){}
        explicit TQuaternion<T>(ConstType w, ConstType x, ConstType y, ConstType z) : w(w), x(x), y(y), z(z){}
        explicit TQuaternion<T>(ConstType w, const TVector3<T>& xyz) : x(xyz.x), y(xyz.y), z(xyz.z), w(w){}

        Type& operator[](int i)
        { return (&x)[i]; }

        ConstType operator[](int i) const
        { return (&x)[i]; }

		static const TQuaternion<T> Identity;
    };

	template<typename T>
	const TQuaternion<T> TQuaternion<T>::Identity = TQuaternion<T>(1, 0, 0, 0);


    //Matrices
    template<typename T>
    struct TMatrix44
    {
        enum ctor{null};

        typedef T Type;
        typedef T const& ConstType;
        TVector4<T> value[4];

        typedef TVector4<T> ColType;
        typedef const ColType ConstColType;

        TMatrix44<T>(ctor){}	 // dont zero memory
        TMatrix44<T>(void)		//default ctor
        {
            value[0] = ColType(1, 0, 0, 0);
            value[1] = ColType(0, 1, 0, 0);
            value[2] = ColType(0, 0, 1, 0);
            value[3] = ColType(0, 0, 0, 1);
        }
        // ident matrix make
        TMatrix44<T>(
                const T c00, const T c01, const T c02, const T c03,
                const T c10, const T c11, const T c12, const T c13,
                const T c20, const T c21, const T c22, const T c23,
                const T c30, const T c31, const T c32, const T c33
                )
        {
            value[0] = ColType(c00, c01, c02, c03);
            value[1] = ColType(c10, c11, c12, c13);
            value[2] = ColType(c20, c21, c22, c23);
            value[3] = ColType(c30, c31, c32, c33);
        } // ident matrix make

        explicit TMatrix44<T>(ConstColType v0, ConstColType v1, ConstColType v2, ConstColType v3)
        {
            value[0] = v0;
            value[1] = v1;
            value[2] = v2;
            value[3] = v3;
        }

        ColType& operator[](int i)
        { return value[i]; }

        ConstColType& operator[](int i) const
        { return value[i]; }
    };



    //Other's
    template<typename T>
    struct TAABB
    {
        enum ctor{null};

        typedef T Type;
        typedef T const& ConstType;
        TVector3<T> min;
        TVector3<T> max;
        TAABB<T>(ctor){} // dont zero memory
        TAABB<T>(void){} //
        explicit TAABB<T>(TVector3<T> min, TVector3<T> max): min(min), max(max){}

        TVector3<T> Center() const { return (min + max) * 0.5; }

        bool IsInfinity() const
        {
            T dot = Dot(min, max);
            return dot != dot;
        }

        T DistanceSqr(TVector3<T> v) const
        {
            const TVector3<T> halfSize((max - min) * T(0.5));
            // work in the box's coordinate system
            const TVector3<T> kDiff(v - (halfSize + min));
            // compute squared distance and closest point on box
            T fSqrDistance(T(0.0));
            for(uint i = 0; i < 3; ++i )
            {
                const T kClosest(kDiff[i]);
                const T khalfSize(halfSize[i]);
                if( kClosest < -khalfSize )
                {
                    const T fDelta(kClosest + khalfSize);
                    fSqrDistance += fDelta * fDelta;
                }
                else if( kClosest > khalfSize )
                {
                    const T fDelta(kClosest - khalfSize);
                    fSqrDistance += fDelta * fDelta;
                }
            }
            return fSqrDistance;
        }

        T Distance(TVector3<T> v) const
        {
            return Sqrt<T>(DistanceSqr(v));
        }

		static const TAABB<T> Infinity;
    };

	template<typename T>
	const TAABB<T> TAABB<T>::Infinity(-Math::Infinity<T>(), Math::Infinity<T>());

    template<typename T>
    struct TPlane
    {
        TVector3<T> Normal;
        T Distance;
        TPlane(const TVector3<T>& normal, T distance)
            : Normal(normal), Distance(distance)
        {}
    };

    template<typename T>
    struct TSphere
    {
        TVector3<T> Center;
        T Radius;
        TSphere(const TVector3<T>& center, T radius)
            : Center(center), Radius(radius)
        {}
    };


    template<typename T>
    struct TRay
    {
        TVector3<T> Origin;
        TVector3<T> Direction;
        explicit TRay<T>(TVector3<T> origin, TVector3<T> direction)
            : Origin(origin), Direction(direction)
        {}

        bool IntersectSide(T pos, T dir, T min, T max, T& tMin, T& tMax) const
        {
            T t0, t1;

            if((dir > -Epsilon<T>()) && (dir < +Epsilon<T>()))
            {
                return (pos >= min) && (pos <= max);
            }
            else
            {
                dir = T(1) / dir;
            }

            if(dir > T(0))
            {
                t0 = (min - pos) * dir;
                t1 = (max - pos) * dir;
            }
            else
            {
                t0 = (max - pos) * dir;
                t1 = (min - pos) * dir;
            }


            if (t0 > tMin) tMin = t0;
            if (t1 < tMax) tMax = t1;

            return (tMax > tMin) && (tMax > T(0));
        }

        bool Intersect(const TAABB<T>& aabb, T& dist) const
        {
            T tMin = -Infinity<T>();
            T tMax = +Infinity<T>();

            if((IntersectSide(Origin.x, Direction.x, aabb.min.x, aabb.max.x, tMin, tMax)) &&
                    (IntersectSide(Origin.y, Direction.y, aabb.min.y, aabb.max.y, tMin, tMax)) &&
                    (IntersectSide(Origin.z, Direction.z, aabb.min.z, aabb.max.z, tMin, tMax)))
            {
                dist = tMin;
                return true;
            }
            else
            {
                return false;
            }
        }

        TVector3<T> Intersect(const TPlane<T>& plane, T offsetHeight) const
        {
            T d = Dot(Direction, plane.Normal);
            if(((d > Epsilon2<T>()) || (d < -Epsilon2<T>())))
            {
                const TVector3<T> sp = TVector3<T>(0, offsetHeight, 0) - Origin;
                d = T(1) / d;
                T t = Dot(sp, plane.Normal) * d;
                if(t > T(0))
                {
                    return Origin + (Direction * t);
                }
            }

            return TVector3<T>(T(0)); //this for see in center - TODO : Use NaN
        }

        TVector3<T> Intersect(const TSphere<T>& sphere) const
        {
            TVector3<T> dst = Origin - sphere.Center;
            T B = Dot(dst, Direction);
            T C = Dot(dst, dst) - sphere.Radius*sphere.Radius;
            T D = B*B - C;
            T t = 0;

            if (D>0)
            {
                if (Length(Origin - sphere.Center) < sphere.Radius)
                {
                    t = -B + Sqrt(D);
                }
                else
                {
                    t = -B - Sqrt(D);
                }

                //if((t > aRay.tMin)&&(t < aRay.tMax)&&(t < oHitInfo.dist))
                {
                    return Origin + (Direction * t);
                }
            }
            return TVector3<T>(0, 0, 0);
        }
    };


	template<typename T>
	struct TColor
	{
		enum ctor{null};

		T r;
		T g;
		T b;
		T a;

		TColor(ctor)
		{
		}

		TColor(T r = 1, T g = 1, T b = 1, T a = 1) : r(r), g(g), b(b), a(a)
		{}	

		static const TColor<T> White;
	};

	template<typename T>
	const TColor<T> TColor<T>::White(1, 1, 1, 1);

	template<typename T>
	struct TRect
	{
		enum ctor{null};

		T left;
		T top;
		T right;
		T bottom;

		TRect(ctor)
		{
		}

		TRect(T left, T top, T right, T bottom) : left(left), top(top), right(right), bottom(bottom)
		{}

		static const TRect<T> Identity;
			
	};

	template<typename T>
	const TRect<T> TRect<T>::Identity = TRect<T>((T)0, (T)0, (T)1, (T)1);
    //
    //Template to type declaration
    //


    //
    //Implementation
    //

    //
    // Sqr
    //
    template<typename T>
    inline T Sqr(const TVector3<T>& v)
    {
        return (v.x * v.x) + (v.y * v.y) + (v.z * v.z);
    }

    template<typename T>
    inline T Sqr(const TVector4<T>& v)
    {
        return (v.x * v.x) + (v.y * v.y) + (v.z * v.z) + (v.w * v.w);
    }

    template<typename T>
    inline T Sqr(const TQuaternion<T>& v)
    {
        return  (v.w * v.w) + (v.x * v.x) + (v.y * v.y) + (v.z * v.z);
    }

    template<typename T>
    inline T Clamp(const T v, const T minVal, const T maxVal)
    {
        //TODO: Optimize
        if(v >= maxVal) return maxVal;
        if(v <= minVal) return minVal;
        return v;
    }

    template<typename T>
    inline TVector3<T> Clamp(const TVector3<T>& v, const T minVal, const T maxVal)
    {
        return TVector3<T>(
                    Clamp(v.x, minVal, maxVal),
                    Clamp(v.y, minVal, maxVal),
                    Clamp(v.z, minVal, maxVal));
    }

    //
    // operator+
    //
    template<typename T>
    inline TVector2<T> operator+(const TVector2<T>& v1, const TVector2<T>& v2)
    {
        return TVector2<T>(
                    v1.x + v2.x,
                    v1.y + v2.y);
    }

    template<typename T>
    inline TVector3<T> operator+(const TVector3<T>& v1, const TVector3<T>& v2)
    {
        return TVector3<T>(
                    v1.x + v2.x,
                    v1.y + v2.y,
                    v1.z + v2.z);
    }

    template<typename T>
    inline TVector3<T> operator+=(TVector3<T>& v1, const TVector3<T>& v2)
    {
        return TVector3<T>(
                    v1.x += v2.x,
                    v1.y += v2.y,
                    v1.z += v2.z);
    }

    template<typename T>
    inline TVector3<T> operator+(const TVector3<T>& v1, const T v2)
    {
        return TVector3<T>(
                    v1.x + v2,
                    v1.y + v2,
                    v1.z + v2);
    }

    template<typename T>
    inline TVector4<T> operator+(const TVector4<T>& v1, const TVector4<T>& v2)
    {
        return TVector4<T>(
                    v1.x + v2.x,
                    v1.y + v2.y,
                    v1.z + v2.z,
                    v1.w + v2.w);
    }

    template<typename T>
    inline TVector4<T> operator+(const TVector4<T>& v1, const T v2)
    {
        return TVector4<T>(
                    v1.x + v2,
                    v1.y + v2,
                    v1.z + v2,
                    v1.w + v2);
    }

    template<typename T>
    inline TQuaternion<T> operator+(const TQuaternion<T>& lhs, const TQuaternion<T>& rhs)
    {
        return TQuaternion<T>(
                    lhs.w + rhs.w,
                    lhs.x + rhs.x,
                    lhs.y + rhs.y,
                    lhs.z + rhs.z);
    }

    //
    // operator-
    //
    template<typename T>
    inline TVector2<T> operator-(const TVector2<T>& v1, const TVector2<T>& v2)
    {
        return TVector2<T>(
                    v1.x - v2.x,
                    v1.y - v2.y);
    }

    template<typename T>
    inline TVector3<T> operator-(const TVector3<T>& v1, const TVector3<T>& v2)
    {
        return TVector3<T>(
                    v1.x - v2.x,
                    v1.y - v2.y,
                    v1.z - v2.z);
    }

    template<typename T>
    inline TVector4<T> operator-(const TVector4<T>& v1, const TVector4<T>& v2)
    {
        return TVector4<T>(
                    v1.x - v2.x,
                    v1.y - v2.y,
                    v1.z - v2.z,
                    v1.w - v2.w);
    }
    template<typename T>
    inline TVector3<T> operator-(const TVector3<T>& v1)
    {
        return TVector3<T>(
                    -v1.x,
                    -v1.y,
                    -v1.z);
    }

    template<typename T>
    inline TVector4<T> operator-(const TVector4<T>& v1, const T v2)
    {
        return TVector4<T>(v1.x - v2,
                           v1.y - v2,
                           v1.z - v2,
                           v1.w - v2);
    }

    //
    // operator/
    //
    template<typename T>
    inline TVector2<T> operator/(const TVector2<T>& v1, const TVector2<T>& v2)
    {
        return TVector2<T>(
                    v1.x / v2.x,
                    v1.y / v2.y);
    }

    template<typename T>
    inline TVector3<T> operator/(const TVector3<T>& v1, const TVector3<T>& v2)
    {
        return TVector3<T>(
                    v1.x / v2.x,
                    v1.y / v2.y,
                    v1.z / v2.z);
    }

    template<typename T>
    inline TVector3<T> operator/(const TVector3<T>& v1, const T v2)
    {
        return TVector3<T>(
                    v1.x / v2,
                    v1.y / v2,
                    v1.z / v2);
    }

    template<typename T>
    inline TVector4<T> operator/(const TVector4<T>& v1, const T v2)
    {
        return TVector4<T>(
                    v1.x / v2,
                    v1.y / v2,
                    v1.z / v2,
                    v1.w / v2);
    }

    template<typename T>
    inline TVector4<T> operator/=(TVector4<T>& v1, const T v2)
    {
        return TVector4<T>(
                    v1.x /= v2,
                    v1.y /= v2,
                    v1.z /= v2,
                    v1.w /= v2);
    }

    template<typename T>
    inline TQuaternion<T> operator/(const TQuaternion<T>& q, const T v)
    {
        return TQuaternion<T>(q.w / v, TVector3<T>(q.x / v,q.y / v, q.z / v));
    }

    template<typename T>
    inline TMatrix44<T> operator/(const TMatrix44<T>& m, const T v)
    {
        return TMatrix44<T>(m[0] / v, m[1] / v, m[2] / v, m[3] / v);
    }

    template<typename T>
    inline TMatrix44<T> operator/=(TMatrix44<T>& m, const T v)
    {
        return TMatrix44<T>(m[0] /= v, m[1] /= v, m[2] /= v, m[3] /= v);
    }

    //
    // operator*
    //
    template<typename T>
    inline TVector3<T> operator*=(TVector3<T>& v1, const T v)
    {
        return TVector3<T>(
                    v1.x *= v,
                    v1.y *= v,
                    v1.z *= v);
    }

    template<typename T>
    inline TVector3<T> operator*(const TVector3<T>& v1, const T v)
    {
        return TVector3<T>(
                    v1.x * v,
                    v1.y * v,
                    v1.z * v);
    }

    template<typename T>
    inline TVector3<T> operator*(const T v, const TVector3<T>& v1)
    {
        return v1 * v;
    }

    template<typename T>
    inline TVector3<T> operator*(const TVector3<T>& v1, const TVector3<T>& v2)
    {
        return TVector3<T>(
                    v1.x * v2.x,
                    v1.y * v2.y,
                    v1.z * v2.z);
    }

    template<typename T>
    inline TVector3<T> operator*(const TQuaternion<T>& q, const TVector3<T>& v)
    {
        const T Two(2);

        TVector3<T> uv, uuv;
        TVector3<T> QuatVector(q.x, q.y, q.z);
        uv = Cross(QuatVector, v);
        uuv = Cross(QuatVector, uv);
        uv *= (Two * q.w);
        uuv *= Two;

        return v + uv + uuv;
    }

    template<typename T>
    inline TVector4<T> operator*(const TVector4<T>& v1, const TVector4<T>& v2)
    {
        return TVector4<T>(v1.x * v2.x,
                           v1.y * v2.y,
                           v1.z * v2.z,
                           v1.w * v2.w);
    }

    template<typename T>
    inline TVector4<T> operator*(const TVector4<T>& v1, const T v2)
    {
        return TVector4<T>(v1.x * v2,
                           v1.y * v2,
                           v1.z * v2,
                           v1.w * v2);
    }

    template<typename T>
    inline TVector4<T> operator*(const TMatrix44<T>& m, const TVector4<T>& v)
    {
        return TVector4<T>(
                    m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w,
                    m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w,
                    m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w,
                    m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z + m[3][3] * v.w);
    }

	template<typename T>
	inline TVector3<T> operator*(const TMatrix44<T>& m, const TVector3<T>& v)
	{
		T fInvW = (T)1 / 
			(m[0][3] * v.x 
			+m[1][3] * v.y 
			+m[2][3] * v.z
			+m[3][3]);

		return TVector3<T>(
			(m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0]) * fInvW,
			(m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1]) * fInvW,
			(m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2]) * fInvW);
	}

    template<typename T>
    inline TQuaternion<T> operator*(const TQuaternion<T>& q, const T v)
    {
        return TQuaternion<T>(
                    q.w * v,
                    q.x * v,
                    q.y * v,
                    q.z * v);
    }

    template<typename T>
    inline TQuaternion<T> operator*(const TQuaternion<T>& q1, const TQuaternion<T>& q2)
    {
        TQuaternion<T> tmp(TQuaternion<T>::null);
        tmp.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
        tmp.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z;
        tmp.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x;
        tmp.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;

        return tmp;
    }

    template<typename T>
    inline TMatrix44<T> operator*(const TMatrix44<T>& m1, const TMatrix44<T>& m2)
    {
        const TVector4<T> SrcA0 = m1[0];
        const TVector4<T> SrcA1 = m1[1];
        const TVector4<T> SrcA2 = m1[2];
        const TVector4<T> SrcA3 = m1[3];

        const TVector4<T> SrcB0 = m2[0];
        const TVector4<T> SrcB1 = m2[1];
        const TVector4<T> SrcB2 = m2[2];
        const TVector4<T> SrcB3 = m2[3];

        TMatrix44<T> Result(TMatrix44<T>::null);
        Result[0] = SrcA0 * SrcB0[0] + SrcA1 * SrcB0[1] + SrcA2 * SrcB0[2] + SrcA3 * SrcB0[3];
        Result[1] = SrcA0 * SrcB1[0] + SrcA1 * SrcB1[1] + SrcA2 * SrcB1[2] + SrcA3 * SrcB1[3];
        Result[2] = SrcA0 * SrcB2[0] + SrcA1 * SrcB2[1] + SrcA2 * SrcB2[2] + SrcA3 * SrcB2[3];
        Result[3] = SrcA0 * SrcB3[0] + SrcA1 * SrcB3[1] + SrcA2 * SrcB3[2] + SrcA3 * SrcB3[3];
        return Result;
    }

    template<typename T>
    inline TAABB<T> operator*(const TMatrix44<T> m, const TAABB<T>& aabbox)
    {
        const TVector4<T>& tmp = m[3];
        const TVector3<T> tmpMax(tmp.x, tmp.y, tmp.z);

        TAABB<T> retVal = TAABB<T>(tmpMax, tmpMax);

        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                T av = m[j][i] * aabbox.min[j];
                T bv = m[j][i] * aabbox.max[j];
                if (av < bv)
                {
                    retVal.min[i] += av;
                    retVal.max[i] += bv;
                }
                else
                {
                    retVal.min[i] += bv;
                    retVal.max[i] += av;
                }
            }
        }
        return retVal;
    }


    //
    // Length
    //
    template<typename T>
    inline T Length(const TVector3<T>& x)
    {
        return Sqrt(Sqr(x));
    }

    template<typename T>
    inline T Length(const TQuaternion<T>& q)
    {
        return Sqrt(Dot(q, q));
    }

    //
    // Distance
    //
    template<typename T>
    inline T Distance(const TVector3<T>& x, const TVector3<T>& y)
    {
        return Length(x - y);
    }
    //
    // Normalize
    //
    template<typename T>
    inline TVector3<T> Normalize(const TVector3<T>& v)
    {
        T sqr = Sqr(v);
        if(sqr < Epsilon<T>())
        {
            return TVector3<T>(T(0));
        }
        else
        {
            const T InvSqrt = InverseSqrt(sqr);
            return TVector3<T>(v * InvSqrt);
        }
    }

    template<typename T>
    inline TVector4<T> Normalize(const TVector4<T>& v)
    {
        const T InvSqrt = InverseSqrt(Sqr(v));
        return TVector4<T>(v * InvSqrt);
    }

    template<typename T>
    inline TQuaternion<T> Normalize(const TQuaternion<T>& q)
    {
        const T InvSqrt = InverseSqrt(Sqr(q));
        return TQuaternion<T>(q * InvSqrt);
    }

    //
    // Cross
    //
    template<typename T>
    inline TVector3<T> Cross(const TVector3<T>& x, const TVector3<T>& y)
    {
        return TVector3<T>(
                    x.y * y.z - y.y * x.z,
                    x.z * y.x - y.z * x.x,
                    x.x * y.y - y.x * x.y);
    }

    template<typename T>
    inline T Dot(const TVector3<T>& x, const TVector3<T>& y)
    {
        return x.x * y.x + x.y * y.y + x.z * y.z;
    }

    template<typename T>
    inline T Dot(const TVector4<T>& x, const TVector4<T>& y)
    {
        return x.x * y.x + x.y * y.y + x.z * y.z + x.w * y.w;
    }

    template<typename T>
    inline T Dot(const TQuaternion<T>& q1, const TQuaternion<T>& q2)
    {
        return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w;
    }

    //
    // Inverse
    //
    template<typename T>
    inline TQuaternion<T> Inverse(const TQuaternion<T>& q)
    {
        return Conjugate(q) / Length(q);
    }

    template<typename T>
    inline TMatrix44<T> Inverse(const TMatrix44<T>& m)
    {
        T m00 = m[0][0], m01 = m[0][1], m02 = m[0][2], m03 = m[0][3];
        T m10 = m[1][0], m11 = m[1][1], m12 = m[1][2], m13 = m[1][3];
        T m20 = m[2][0], m21 = m[2][1], m22 = m[2][2], m23 = m[2][3];
        T m30 = m[3][0], m31 = m[3][1], m32 = m[3][2], m33 = m[3][3];

        T v0 = m20 * m31 - m21 * m30;
        T v1 = m20 * m32 - m22 * m30;
        T v2 = m20 * m33 - m23 * m30;
        T v3 = m21 * m32 - m22 * m31;
        T v4 = m21 * m33 - m23 * m31;
        T v5 = m22 * m33 - m23 * m32;

        T t00 = + (v5 * m11 - v4 * m12 + v3 * m13);
        T t10 = - (v5 * m10 - v2 * m12 + v1 * m13);
        T t20 = + (v4 * m10 - v2 * m11 + v0 * m13);
        T t30 = - (v3 * m10 - v1 * m11 + v0 * m12);

        T invDet = 1 / (t00 * m00 + t10 * m01 + t20 * m02 + t30 * m03);

        T d00 = t00 * invDet;
        T d10 = t10 * invDet;
        T d20 = t20 * invDet;
        T d30 = t30 * invDet;

        T d01 = - (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
        T d11 = + (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
        T d21 = - (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
        T d31 = + (v3 * m00 - v1 * m01 + v0 * m02) * invDet;

        v0 = m10 * m31 - m11 * m30;
        v1 = m10 * m32 - m12 * m30;
        v2 = m10 * m33 - m13 * m30;
        v3 = m11 * m32 - m12 * m31;
        v4 = m11 * m33 - m13 * m31;
        v5 = m12 * m33 - m13 * m32;

        T d02 = + (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
        T d12 = - (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
        T d22 = + (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
        T d32 = - (v3 * m00 - v1 * m01 + v0 * m02) * invDet;

        v0 = m21 * m10 - m20 * m11;
        v1 = m22 * m10 - m20 * m12;
        v2 = m23 * m10 - m20 * m13;
        v3 = m22 * m11 - m21 * m12;
        v4 = m23 * m11 - m21 * m13;
        v5 = m23 * m12 - m22 * m13;

        T d03 = - (v5 * m01 - v4 * m02 + v3 * m03) * invDet;
        T d13 = + (v5 * m00 - v2 * m02 + v1 * m03) * invDet;
        T d23 = - (v4 * m00 - v2 * m01 + v0 * m03) * invDet;
        T d33 = + (v3 * m00 - v1 * m01 + v0 * m02) * invDet;

        return TMatrix44<T>(
            d00, d01, d02, d03,
            d10, d11, d12, d13,
            d20, d21, d22, d23,
            d30, d31, d32, d33);

		/*
        //return m;
        const T Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
        const T Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
        const T Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];

        const T Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
        const T Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
        const T Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];

        const T Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
        const T Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
        const T Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];

        const T Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
        const T Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
        const T Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];

        const T Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
        const T Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
        const T Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];

        const T Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
        const T Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
        const T Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];

        TVector4<T> const SignA(+1, -1, +1, -1);
        TVector4<T> const SignB(-1, +1, -1, +1);

        TVector4<T> fac0(Coef00, Coef00, Coef02, Coef03);
        TVector4<T> fac1(Coef04, Coef04, Coef06, Coef07);
        TVector4<T> fac2(Coef08, Coef08, Coef10, Coef11);
        TVector4<T> fac3(Coef12, Coef12, Coef14, Coef15);
        TVector4<T> fac4(Coef16, Coef16, Coef18, Coef19);
        TVector4<T> fac5(Coef20, Coef20, Coef22, Coef23);

        TVector4<T> vec0(m[1][0], m[0][0], m[0][0], m[0][0]);
        TVector4<T> vec1(m[1][1], m[0][1], m[0][1], m[0][1]);
        TVector4<T> vec2(m[1][2], m[0][2], m[0][2], m[0][2]);
        TVector4<T> vector3(m[1][3], m[0][3], m[0][3], m[0][3]);

        TVector4<T> Inv0 = SignA * (vec1 * fac0 - vec2 * fac1 + vector3 * fac2);
        TVector4<T> Inv1 = SignB * (vec0 * fac0 - vec2 * fac3 + vector3 * fac4);
        TVector4<T> Inv2 = SignA * (vec0 * fac1 - vec1 * fac3 + vector3 * fac5);
        TVector4<T> Inv3 = SignB * (vec0 * fac2 - vec1 * fac4 + vec2 * fac5);

        TMatrix44<T> inverse(Inv0, Inv1, Inv2, Inv3);

        TVector4<T> Row0(inverse[0][0], inverse[1][0], inverse[2][0], inverse[3][0]);

        T Determinant = Math::Dot(m[0], Row0);

        inverse /= Determinant;

        return inverse;*/
    }



    //
    // UnProject
    //
    template <typename T>
    inline TVector3<T> UnProject(const TVector2<T>& pos, T z, const TMatrix44<T>& viewProj, const TVector2<T>& view)
    {
        TMatrix44<T> inv = Inverse(viewProj);

        TVector4<T> tmp = TVector4<T>(pos.x, pos.y, z, T(1));
        tmp.x = (tmp.x) / T(view.x);
        tmp.y = (tmp.y) / T(view.y);
        tmp = tmp * T(2);
        tmp = tmp - T(1);

        TVector4<T> obj = inv * tmp;
        obj /= obj.w;

        return TVector3<T>(obj.x, obj.y, obj.z);
    }

    //
    // ToAxisAngle
    //
    template<typename T>
    void ToAxisAngle(TVector3<T> &axis, T &angle, const TQuaternion<T>& q)
    {
        T scale = Sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
        axis = axis / scale;
        angle = ACos(q.w) * T(2);
    }

    template<typename T>
    TMatrix44<T> ToMatrix(const TQuaternion<T>& q)
    {
        // Converts this quaternion to a rotation matrix.
        //
        //  | 1 - 2(y^2 + z^2)	2(xy + wz)			2(xz - wy)			0  |
        //  | 2(xy - wz)		1 - 2(x^2 + z^2)	2(yz + wx)			0  |
        //  | 2(xz + wy)		2(yz - wx)			1 - 2(x^2 + y^2)	0  |
        //  | 0					0					0					1  |

        T x2 = q.x + q.x;
        T y2 = q.y + q.y;
        T z2 = q.z + q.z;
        T xx = q.x * x2;
        T xy = q.x * y2;
        T xz = q.x * z2;
        T yy = q.y * y2;
        T yz = q.y * z2;
        T zz = q.z * z2;
        T wx = q.w * x2;
        T wy = q.w * y2;
        T wz = q.w * z2;

        TMatrix44<T> m;

        m[0][0] = 1.0f - (yy + zz);
        m[0][1] = xy + wz;
        m[0][2] = xz - wy;
        m[0][3] = 0.0f;

        m[1][0] = xy - wz;
        m[1][1] = 1.0f - (xx + zz);
        m[1][2] = yz + wx;
        m[1][3] = 0.0f;

        m[2][0] = xz + wy;
        m[2][1] = yz - wx;
        m[2][2] = 1.0f - (xx + yy);
        m[2][3] = 0.0f;

        return m;
    }

    template<typename T>
    TQuaternion<T> FromMatrix(const TMatrix44<T> m)
    {
        // Creates a quaternion from a rotation matrix.
        // The algorithm used is from Allan and Mark Watt's "Advanced
        // Animation and Rendering Techniques" (ACM Press 1992).

        T s = 0.0f;

        TQuaternion<T> q(0.0f);

        T trace = m[0][0] + m[1][1] + m[2][2];

        if (trace > 0.0f)
        {
            s = Sqrt(trace + 1.0f);
            q[3] = s * 0.5f;
            s = 0.5f / s;
            q[0] = (m[1][2] - m[2][1]) * s;
            q[1] = (m[2][0] - m[0][2]) * s;
            q[2] = (m[0][1] - m[1][0]) * s;
        }
        else
        {
            int nxt[3] = {1, 2, 0};
            int i = 0, j = 0, k = 0;

            if (m[1][1] > m[0][0])
                i = 1;

            if (m[2][2] > m[i][i])
                i = 2;

            j = nxt[i];
            k = nxt[j];
            s = Sqrt((m[i][i] - (m[j][j] + m[k][k])) + 1.0f);

            q[i] = s * 0.5f;
            s = 0.5f / s;
            q[3] = (m[j][k] - m[k][j]) * s;
            q[j] = (m[i][j] + m[j][i]) * s;
            q[k] = (m[i][k] + m[k][i]) * s;
        }
        return q;
    }

    //
    // Position
    //
    template<typename T>
    inline void Position(TMatrix44<T>& m, const TVector3<T>& pos)
    {
        m[3][0] = pos.x;
        m[3][1] = pos.y;
        m[3][2] = pos.z;
    }

    //
    // Rotate
    //
    template<typename T>
    inline TVector3<T> Rotate(const TQuaternion<T> &q, const TVector3<T> &v)
    {
        return TVector3<T>(q * v);
    }

    template<typename T>
    inline TQuaternion<T> Rotate(const TVector3<T> &v, const TRadian<T>& angle)
    {
        T sinAngle = Sin(angle.value * T(0.5));
        T cosAngle = Cos(angle.value * T(0.5));
        return TQuaternion<T>(cosAngle, Normalize(v) * sinAngle);
    }

    template<typename T>
    inline void Rotate(TMatrix44<T>& m, const TQuaternion<T>& q)
    {
        m[0][0] = 1.0f - 2.0f * (q.y * q.y + q.z * q.z);
        m[0][1] = 2.0f * (q.x * q.y - q.w * q.z);
        m[0][2] = 2.0f * (q.x * q.z + q.w * q.y);

        // 2nd row
        m[1][0] = 2.0f * (q.x * q.y + q.w * q.z);
        m[1][1] = 1.0f - 2.0f * (q.x * q.x + q.z * q.z);
        m[1][2] = 2.0f * (q.y * q.z - q.w * q.x);

        // 3rd row
        m[2][0] = 2.0f * (q.x * q.z - q.w * q.y);
        m[2][1] = 2.0f * (q.y * q.z + q.w * q.x);
        m[2][2] = 1.0f - 2.0f * (q.x * q.x + q.y * q.y);
    }

    template<typename T>
    inline void RotateAndScale(TMatrix44<T>& m, const TQuaternion<T>& q, const TVector3<T>& s)
    {
        m[0][0] = (1.0f - 2.0f * (q.y * q.y + q.z * q.z))	* s.x;
        m[0][1] = (2.0f * (q.x * q.y - q.w * q.z))			* s.x;
        m[0][2] = (2.0f * (q.x * q.z + q.w * q.y))			* s.x;

        // 2nd row
        m[1][0] = (2.0f * (q.x * q.y + q.w * q.z))			* s.y;
        m[1][1] = (1.0f - 2.0f * (q.x * q.x + q.z * q.z))	* s.y;
        m[1][2] = (2.0f * (q.y * q.z - q.w * q.x))			* s.y;

        // 3rd row
        m[2][0] = (2.0f * (q.x * q.z - q.w * q.y))			* s.z;
        m[2][1] = (2.0f * (q.y * q.z + q.w * q.x))			* s.z;
        m[2][2] = (1.0f - 2.0f * (q.x * q.x + q.y * q.y))	* s.z;
    }
    //
    // Conjugate
    //
    template<typename T>
    inline TQuaternion<T> Conjugate(const TQuaternion<T>& q)
    {
        return TQuaternion<T>(
                    q.w,
                    TVector3<T>(-q.x, -q.y, -q.z));
    }

    //
    // Translate
    //
    template<typename T>
    inline TMatrix44<T> Translate(const TMatrix44<T>& m, const TVector3<T>& v)
    {
        TMatrix44<T> Result(m);
        Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];
        return Result;
    }

    //
    // LookAt
    //

    template<typename T>
    inline bool isZeroLength(const TVector3<T>& v)
    {
        return (v.x * v.x + v.y * v.y + v.z * v.z) < (1e-06 * 1e-06);
    }

    template<typename T>
    inline TQuaternion<T> RotationTo(const TVector3<T>& axis, const TVector3<T>& direction/*, const TVector3<T>& fallbackAxis = Zero*/)
    {
        // Based on Stan Melax's article in Game Programming Gems
        TQuaternion<T> q;
        // Copy, since cannot modify local
        TVector3<T> v0 = Normalize(axis);
        TVector3<T> v1 = Normalize(direction);

        T d = Dot(v0, v1);

        // If dot == 1, vectors are the same
        if (d >= 1.0f)
        {
            return TQuaternion<T>(); // return ident
        }

        if (d < (1e-6f - 1.0f))
        {
            //negative axis
            //q = RotationTo(-axis, direction);
            q = Rotate(TVector3<T>(0, 1, 0), TRadian<T>(PI<T>()));
        }
        else
        {
            T s = Sqrt((1+d)*2);
            T invs = T(1) / s;

            TVector3<T> c = Cross(v0, v1);
            q = Normalize(TQuaternion<T>(s * 0.5f, c * invs));
        }
        return q;
    }

    template<typename T>
    inline TMatrix44<T> LookAt(const TVector3<T>& eye, const TVector3<T>& center, const TVector3<T>& up)
    {
        TVector3<T> f = Normalize(center - eye);
        TVector3<T> u = Normalize(up);
        TVector3<T> s = Normalize(Cross(f, u));
        u = Cross(s, f);

        TMatrix44<T> Result;
        Result[0][0] = s.x;
        Result[1][0] = s.y;
        Result[2][0] = s.z;
        Result[0][1] = u.x;
        Result[1][1] = u.y;
        Result[2][1] = u.z;
        Result[0][2] =-f.x;
        Result[1][2] =-f.y;
        Result[2][2] =-f.z;
        return Translate(Result, -eye);
    }

    template<typename T>
    inline TMatrix44<T> Perspective(const T fovy, const T aspect, const T zNear, const T zFar)
    {
        T range = Tan(TRadian<T>(TDegree<T>(fovy / T(2)))) * zNear;
        T left = -range * aspect;
        T right = range * aspect;
        T bottom = -range;
        T top = range;

        TMatrix44<T> Result;
        Result[0][0] = (T(2) * zNear) / (right - left);
        Result[1][1] = (T(2) * zNear) / (top - bottom);
        Result[2][2] = - (zFar + zNear) / (zFar - zNear);
        Result[2][3] = - T(1);
        Result[3][2] = - (T(2) * zFar * zNear) / (zFar - zNear);
        return Result;
    }

    template<typename T>
    inline TMatrix44<T> Ortho(const T left, const T right, const T bottom, const T top, const T zNear, const T zFar)
    {
        TMatrix44<T> Result;
        Result[0][0] =	T(2) / (right - left);
        Result[1][1] =	T(2) / (top - bottom);
        Result[2][2] = - T(2) / (zFar - zNear);
        Result[3][0] = - (right + left) / (right - left);
        Result[3][1] = - (top + bottom) / (top - bottom);
        Result[3][2] = - (zFar + zNear) / (zFar - zNear);
        return Result;
    }


    template<typename T>
    inline TQuaternion<T> ShortestArc(const TVector3<T>& from, const TVector3<T>& to)
    {
        TQuaternion<T> q(Dot(from, to), Cross(from, to));
        q = Normalize(q); // if "from" or "to" not unit, normalize quat
        q.w += 1.0f;      // reducing angle to halfangle
        if(q.w <= Epsilon<T>()) // angle close to PI
        {
            if((from.z*from.z ) > (from.x*from.x))
            {
                q = TQuaternion<T>(q.w, 0, from.z, -from.y); //from*vector3(1,0,0)
            }
            else
            {
                q = TQuaternion<T>(q.w, from.y, -from.x, 0); //from*vector3(0,0,1)
            }
        }
        return Normalize(q);
    }


    template<typename T>
    inline TVector3<T> Lerp(const TVector3<T>& from, const TVector3<T>& to, T weight)
    {
        return (from) + (to - from) * weight;
    }

    template<typename T>
    inline TQuaternion<T> Lerp(const TQuaternion<T>& from, const TQuaternion<T>& to, T weight)
    {
        /*
  // calc cosine theta
  T d = Dot(from, to);

  TQuaternion<T> end = to;
  if(d < 0.0f)
  {
   end.x = -end.x;   // Reverse all signs
   end.y = -end.y;
   end.z = -end.z;
   end.w = -end.w;
  }*/

        T weightInv = 1.0f - weight;
        return Normalize(from*weightInv + to*weight);
    }

    template<typename T>
    inline TQuaternion<T> SLerp(const TQuaternion<T>& from, const TQuaternion<T>& to, T weight)
    {
        // calc cosine theta
        T cosom = Dot(from, to);

        // adjust signs (if necessary)
        TQuaternion<T> end = to;
        if(cosom < 0.0f)
        {
            cosom = -cosom;
            end.x = -end.x;   // Reverse all signs
            end.y = -end.y;
            end.z = -end.z;
            end.w = -end.w;
        }

        // Calculate coefficients
        T sclp, sclq;
        if( (T(1) - cosom) > T(0.0001)) // 0.0001 -> some epsillon
        {
            // Standard case (slerp)
            T omega, sinom;
            omega = ArcCos(cosom); // extract theta from dot product's cos theta
            sinom = Sin(omega);
            sclp  = Sin((T(1) - weight) * omega) / sinom;
            sclq  = Sin(weight * omega) / sinom;
        }
        else
        {
            // Very close, do linear interp (because it's faster)
            sclp = T(1) - weight;
            sclq = weight;
        }

        return from*sclp + end*sclq;
    }

    template<typename T>
    const typename TVector3<T>::Type* ToPtr(const TVector3<T>& v)
    {
        return &(v[0]);
    }
    template<typename T>
    const typename TVector4<T>::Type* ToPtr(const TVector4<T>& v)
    {
        return &(v[0]);
    }
    template<typename T>
    const typename TMatrix44<T>::Type* ToPtr(const TMatrix44<T>& v)
    {
        return &(v[0][0]);
    }

    typedef TVector2<int>		Vector2i;
    typedef TVector2<float>		Vector2;
    typedef TVector3<float>		Vector3;
    typedef TVector4<float>		Vector4;
    typedef TMatrix44<float>	Matrix44;
    typedef TQuaternion<float>	Quaternion;
    typedef TPlane<float>		Plane;
    typedef TSphere<float>		Sphere;
    typedef TAABB<float>		AABB;
    typedef TRay<float>			Ray;
	typedef TRect<float>		Rect;

    typedef TDegree<float>		Degree;
    typedef TRadian<float>		Radian;

	typedef TColor<float>		Color;
	typedef TColor<uint8>		Color255;

    static const float FloatInfinity = Infinity<float>();
    static const float FloatNegInfinity = -Infinity<float>();
}
